import json
import numpy
import math
import sys
import random

users = {}
business = {}
user_ids = []
#user_mean = {}

class BusinessAval:
    def __init__(self):
        self.star = []
        self.user = []
    def appendAval(self, u, s):
        self.star.append(s)
        self.user.append(u)


class UserAval:
    def __init__(self):
        self.star = []
        self.business = []
        self.sumStars = 0.0
        self.sumStarsSquare = 0.0
    def appendAval(self, b, s):
        self.star.append(s)
        self.business.append(b)
        v = float(s)
        self.sumStars = self.sumStars + s
        self.sumStarsSquare = self.sumStarsSquare + s*s
    def stddev(self):
        return math.sqrt(self.sumStarsSquare - self.sumStars)
    def mean(self):
        return self.sumStars/float(len(self.star))


def preprocess():
    global users
    global user_ids
    global user_mean

    json_data=open('yelp_academic_dataset_review.json')
    for line in iter(json_data):
        data = json.loads(line)
        usr =  data['user_id']
        bus = data['business_id']
        if usr not in users:
            users[usr] = UserAval()
        users[usr].appendAval(b = data['business_id'], s = data['stars'])
        if bus not in business:
            business[bus] = BusinessAval()
        business[bus].appendAval(u = usr, s = data['stars'])

    json_data.close()

    json_data=open('yelp_academic_dataset_user.json')

    user_ids = []
    user_mean = {}

    for line in iter(json_data):
        data = json.loads(line)
        usr = data['user_id']
        if len(users[usr].star) > 1:
            if users[usr].stddev() > 0.01:
                user_ids.append(usr)
                user_mean[usr] = float(data['average_stars'])

    json_data.close()




def sim(u1):
    global user_ids
    global users
    #global user_mean
    result = {}
    for u2 in user_ids:
        if u1 == u2:
            continue

        s1 = []
        s2 = []

        for r in range(0, len(users[u1].business)):
            b1 = users[u1].business[r]
            for s in range(0, len(users[u2].business)):
                b2 = users[u2].business[s]
                if b1 == b2:
                    s1.append(users[u1].star[r])
                    s2.append(users[u2].star[s])
                
        if len(s1) > 1:
            s1_array = numpy.array(s1)
            s2_array = numpy.array(s2)
            #mean1 = numpy.mean(s1_array)
            #mean2 = numpy.mean(s2_array)
            mean1 = user_mean[u1]
            mean2 = user_mean[u2]

            #print s1
            #print s2
            #print "mean1: " + str(mean1) + " mean2: " + str(mean2)


            numerador = 0.0
            denominador1 = 0.0
            denominador2 = 0.0
            for k in range(0,len(s1)):
                numerador += (s1[k] - mean1)*(s2[k] - mean2)
                denominador1 += (s1[k] - mean1)*(s1[k] - mean1)
                denominador2 += (s2[k] - mean2)*(s2[k] - mean2)


            denominador = denominador1* denominador2
            if denominador < 0.1:
                continue

            sim = (numerador) / math.sqrt(denominador1*denominador2)
            sim = sim * float(len(s1))
            if (sim > 0.0):
                result[u2] = sim
    return result

def recomenda(u1, sim_list):
    global business
    global users

    result = {}

    bus = []
    for u in sim_list:
        bus += users[u].business

    bus = set(bus)
    for b in bus:
        numerador = 0.0
        denominador = 0.0
        for u, sim in sim_list.iteritems():
            if u in business[b].user:
                denominador += sim
                idx = business[b].user.index(u)
                numerador += sim*(business[b].star[idx] - users[u].mean())
        if denominador > 0.1:
            result[b] = users[u1].mean() + numerador/denominador

    return result

preprocess()

sample = random.sample(user_ids, 1000)
sample_bus = []
sample_star = []
for i in range(0, len(sample)):
    u = sample[i]
    if len(users[u].star) > 1:
        idx_rm = random.randint(0, len(users[u].star) - 1)
        sample_star.append(users[u].star.pop(idx_rm))
        bus = users[u].business.pop(idx_rm)
        sample_bus.append(bus)
        idx = business[bus].user.index(u)
        del business[bus].user[idx]
        del business[bus].star[idx]
        #print u

for i in range(0, len(sample)):
    u = sample[i]
    if len(users[u].star) > 1:
        rec = recomenda(u, sim(u))
        if len(rec) > 0:
            if sample_bus[i] in rec:
                #print u + " " + str(sample_star[i]) + " " + str(rec[sample_bus[i]])
                aval = rec[sample_bus[i]]
                if aval > 5.0:
                    aval = 5.0
                print str(sample_star[i]) + " " + str(aval)